// main.cpp
// 以两个三角形为例

/*
OFF
4 2 0
0 1 0
- 1 0 0
0 - 1 0
1 0 0
3 0 1 2
3 2 3 0
*/

#include <iostream>
#include<Mesh_IO/Mesh_IO.h>
#include<Mesh/libcell_iterator.h>
#include<Algorithm/marching_cubes.h>
#include<Algorithm/points_cloud_algorithm.h>
#include<tool/libcell_kd_node_iterator.h>
#include<tool/libcell_octree_iterator.h>
#include <tool/libcell_tools_kd_node.h>
#include<Algorithm/poisson_construct.h>
#include <tool/libcell_tools_view.h>

#include<Eigen/IterativeLinearSolvers>
#include<Eigen/Sparse>

#include<vector>
#include <tool/viewer_tools.h>
#include <tool/libcell_tools_algorithm.h>
#include<libcell_macros.h>
#include <Math/LB_Quaternions.h>
//
using namespace Eigen;


typedef struct Greedy_Projection_Vert_Prop {
	double normal[3];
	double p[3];
	double theta;
	int is_legal;
	int is_init;
	int active;
}Greedy_Projection_Vert_Prop;

static inline void greedy_projection_vert_prop_init(Greedy_Projection_Vert_Prop* gpvp)
{
	memset(gpvp->normal, 0, sizeof(double) * 3);
	memset(gpvp->p, 0, sizeof(double) * 3);

	gpvp->is_legal = 0;
	gpvp->theta = 0;
	gpvp->is_init = 1;
	gpvp->active = 0;
}

//#define _ReadOff_ LibCell_ReadOff_


//void test_recon_bool()
//{
//    Mesh mesh1,mesh2,mesh3;
//    Mesh_init(&mesh1);    Mesh_init(&mesh2);
//    Mesh_init(&mesh3);
//    _ReadStl_(&mesh1,"boolsamples/dalianjieti02/dljt2.stl");
//    _ReadStl_(&mesh2,"boolsamples/dalianjieti02/gww2.stl");
//
//    _ReadStl_(&mesh3,"ceshi.stl");
//    Mesh* downsampling_through_oc_tree(Node* vertices,int depth);
//
//    for(auto cit=mesh1.c_begin(&mesh1);cit!=mesh1.c_end(&mesh1);cit++)
//    {   
//        quote(cit)->prop=compute_cell_normal(quote(cit));
//    }
//
//    for(auto cit=mesh2.c_begin(&mesh2);cit!=mesh2.c_end(&mesh2);cit++)
//    {   
//        quote(cit)->prop=compute_cell_normal(quote(cit));
//    }
//    
//    printf("mesh1: %d mesh2:%d\n",mesh1.num_v(&mesh1),mesh2.num_v(&mesh2));
//
//    Node*node_v1= create_surface_uniform_sampling_points(&mesh1,8000,0);
//    
//    Node* downsampling_through_size1(Node* vertices,double len );
//
//    for(Node* nit=node_v1;nit!=NULL;nit=(Node*)(nit->Next))
//    {
//        template_v* v=(template_v*)(nit->value);
//        template_c* c=(template_c*)(v->prop);
//        double* normal=(double*)malloc(sizeof(double)*3);
//        memmove(normal,c->prop,sizeof(double)*3);
//        v->prop=normal;
//    }
//    Node* node_v11=downsampling_through_oc_tree(node_v1,6);
//
//    Node*node_v2= create_surface_uniform_sampling_points(&mesh2,8000,0);
//    Node* node_v22=downsampling_through_oc_tree(node_v2,6);
//
//    for(Node* nit=node_v2;nit!=NULL;nit=(Node*)(nit->Next))
//    {
//        template_v* v=(template_v*)(nit->value);
//        template_c* c=(template_c*)(v->prop);
//        double* normal=(double*)malloc(sizeof(double)*3);
//        memmove(normal,c->prop,sizeof(double)*3);
//        v->prop=normal;
//    }
//    KD_Node*kdtree1= create_kd_tree_from_node(node_v1);
//    KD_Node*kdtree2= create_kd_tree_from_node(node_v2);
//
//
//    printf("node v1:%d node v2:%d\n",node_size(node_v1),node_size(node_v2));
//
//    Node* inner_vers1=NULL;
//    double dir[3]={0};
//    for(auto vit= mesh2.v_begin(&mesh2);vit!=mesh2.v_end(&mesh2);vit++)
//    {
//        template_v* v=quote(vit);
//        KD_Node*kdnode=kd_tree_find_nearest(v,kdtree1);
//        
//        Node* n1=kd_tree_find_n_adjacent_verticesn(v,kdtree1,2);
//         dir[0]=kdnode->value->point[0]-v->point[0];
//         dir[1]=kdnode->value->point[1]-v->point[1];
//         dir[2]=kdnode->value->point[2]-v->point[2];
//         normalize(dir,3);
//         double* normal=(double*)(kdnode->value->prop);
//
//         if()
//         {
//
//         }  
//    }  
//
//     double* box=mesh_compute_bounding_box(&mesh1);
//
//     double centroid1[3]={(box[0]+box[3])/2.0,(box[1]+box[4])/2.0,(box[2]+box[5])/2.0};
//     printf("centroid1 : %lf %lf %lf\n",centroid1[0],centroid1[1],centroid1[2]);
//     double max1=box[3]-box[0];
//     max1=((box[4]-box[1])>max1?((box[4]-box[1])):(max1));
//     max1=((box[5]-box[2])>max1?((box[5]-box[2])):(max1));   
//     printf("max1:%lf\n",max1);
//     Node* node_v1=NULL;
//     for(auto vit= mesh1.v_begin(&mesh1);vit!=mesh1.v_end(&mesh1);vit++)
//     {
//         template_v*v=quote(vit);
//         v->point[0]-=centroid1[0];
//         v->point[1]-=centroid1[1];
//         v->point[2]-=centroid1[2];
//         v->point[0]*= (1.9/max1);
//         v->point[1]*= (1.9/max1);
//         v->point[2]*= (1.9/max1);
//         double* normal=(double*)malloc(sizeof(double)*3);
//         memset(normal,0,sizeof(double)*3);
//         v->prop=normal;
//         for(auto vcit=mesh1.vc_begin(&mesh1,*v); vcit!=mesh1.vc_end(&mesh1,*v);vcit++)
//         {
//             normal[0]+=((double*)(quote(vcit)->prop))[0];
//             normal[1]+=((double*)(quote(vcit)->prop))[1];
//             normal[2]+=((double*)(quote(vcit)->prop))[2];
//         }
//         normalize(normal,3);
//         node_v1=node_overlying(node_v1,v);
//     }
//     for(auto vit= mesh2.v_begin(&mesh2);vit!=mesh2.v_end(&mesh2);vit++)
//     {
//         template_v*v=quote(vit);
//         v->point[0]-=centroid1[0];
//         v->point[1]-=centroid1[1];
//         v->point[2]-=centroid1[2];
//         v->point[0]*= (1.9/max1);
//         v->point[1]*= (1.9/max1);
//         v->point[2]*= (1.9/max1);
//         double* normal=(double*)malloc(sizeof(double)*3);
//         memset(normal,0,sizeof(double)*3);
//         v->prop=normal;
//         for(auto vcit=mesh2.vc_begin(&mesh2,*v); vcit!=mesh2.vc_end(&mesh2,*v);vcit++)
//         {
//             normal[0]+=((double*)(quote(vcit)->prop))[0];
//             normal[1]+=((double*)(quote(vcit)->prop))[1];
//             normal[2]+=((double*)(quote(vcit)->prop))[2];
//         }
//         normalize(normal,3);
//     }
//     free(box); 
//     Mesh*nm= create_poisson_reconstruct_mesh(node_v1,128,140);
// 
//     Poisson_Grid*pg1=(Poisson_Grid*)malloc(sizeof(Poisson_Grid));
//     poisson_grid_init(pg1);
//
//     poisson_grid_init_with_depth(pg1,8);
//    
//     fill_normal_coeff(pg1,node_v1);
//
//     poisson_test_sparse_matrix(pg1);
//   
//    
//     double iso1=compute_average_poisson_iso(pg1); 
//     double temp_p[3]={-0.801077 -0.216458 -0.306746};
//     double endfun= end_poisson_space_fun(temp_p,pg1);
//
//     template_v*vv1=quote(mesh1.v_begin(&mesh1));
//
//     printf("%.9lf %.9lf %.9lf\n",vv1->point[0],vv1->point[1],vv1->point[2]);
//     //printf("pow 8:%lf \n",pow(2,8));
//     printf("end fun:%.9lf %.9lf\n",endfun,iso1);
//     poisson_grid_free(pg1);
// 
//    Node * node_v=NULL;
//    Mesh mesh;
//    Mesh_init(&mesh);
//    mesh.dimension=2;mesh.simplex=1; mesh.manifold_require=1;
//     
//     for(auto vit=mesh1.v_begin(&mesh1);vit!=mesh1.v_end(&mesh1);vit++)
//     {
//         Greedy_Projection_Vert_Prop* gpvp=(Greedy_Projection_Vert_Prop*)malloc(sizeof(Greedy_Projection_Vert_Prop));
//         greedy_projection_vert_prop_init(gpvp);
//         for(auto vcit=mesh1.vc_begin(&mesh1,*vit);vcit!=mesh1.vc_end(&mesh1,*vit);vcit++)
//         {
//             gpvp->normal[0]+=((double*)(quote(vcit)->prop))[0];
//             gpvp->normal[1]+=((double*)(quote(vcit)->prop))[1];
//             gpvp->normal[2]+=((double*)(quote(vcit)->prop))[2];
//         }
//         normalize(gpvp->normal,3);
//         template_v* v= mesh.create_vertexv(&mesh,quote(vit)->point,3);
//         v->prop=gpvp;
//         node_v=node_overlying(node_v,v);
//     }
// 
//     for(auto vit=mesh2.v_begin(&mesh2);vit!=mesh2.v_end(&mesh2);vit++)
//     {
//         Greedy_Projection_Vert_Prop* gpvp=(Greedy_Projection_Vert_Prop*)malloc(sizeof(Greedy_Projection_Vert_Prop));
//         greedy_projection_vert_prop_init(gpvp);
//         for(auto vcit=mesh2.vc_begin(&mesh2,*vit);vcit!=mesh2.vc_end(&mesh2,*vit);vcit++)
//         {
//             gpvp->normal[0]+=((double*)(quote(vcit)->prop))[0];
//             gpvp->normal[1]+=((double*)(quote(vcit)->prop))[1];
//             gpvp->normal[2]+=((double*)(quote(vcit)->prop))[2];
//         }
//         normalize(gpvp->normal,3);
//         template_v* v= mesh.create_vertexv(&mesh,quote(vit)->point,3);
//         v->prop=gpvp;
//         node_v=node_overlying(node_v,v);
//     }
//
//
//    Viewer_World_Manager vwm;
//    viewer_world_manager_init(&vwm);
//    Viewer_World *vw=vwm.create_world(&vwm,NULL);
//
//    add_default_somethings(vw);
//     test_show_node_vertices(vw,node_v1);
//
//
//     test_show_mesh_cells(vw,&mesh1);
//     test_show_mesh_cells(vw,&mesh2);
//
//     test_show_mesh_cells(vw,&mesh2);
//
//     test_show_mesh_cells(vw,nm);
//
//    Viewer_Opengl_Interpreter voi;
//    viewer_opengl_interpreter_initn(&voi,&vwm);
//    voi.interpreter(&voi);
//    viewer_opengl_interpreter_free(&voi);
//    viewer_world_manager_free(&vwm);
//
//    Mesh_free(&mesh);
//    Mesh_free(&mesh1);   Mesh_free(&mesh2);
//
//}

void your_test()
{
	Mesh mesh1;
	Mesh_init(&mesh1);
	// 网格
	_ReadOff_(&mesh1, "triangle.off", 3);
	Mesh_free(&mesh1);
}

void print_line() { printf("\n---- ---- ---- ---- ---- ---- ---- ---- ---- ---- \n"); };

// 打印边坐标
void print_sides_edges(Mesh*);

// 打印多边形
void print_cell(Mesh*);



int main(int argc, char* argv[])
{
	std::cout << "read off demo 2024" << std::endl;

	//Init
	Mesh mesh1;
	Mesh_init(&mesh1);

	char offfile[] = "wftest/t1.off";	//指定文件
	// read off file
	if (nullptr == argv[1])
	{
		//_ReadOff_(&mesh1, offfile, 3);	//
	}
	else
	{
		printf("file:%s\n", argv[1]);
		sprintf(offfile, "%s", argv[1]);
	}

	printf("test file name is %s\n", offfile);

	_ReadOff_(&mesh1, offfile, 3);	//

	//_ReadOff_(&mesh1, "bunny.off", 3);	//

	// 边
	print_sides_edges(&mesh1);

	print_line();

	//多边形
	print_cell(&mesh1);


	Mesh_free(&mesh1);

	print_line();
	printf("main end\n");

	return 1;
}

void print_sides_edges(Mesh* p)
{
	printf("print triangle sides ...\n");

	// f_ face 表示物体的边
	for (auto fit = (*p).f_begin(p); fit != (*p).f_end(p); fit++)
	{
		auto at = quote(fit);
		std::cout << "sides id: " << at->id;
		// fv_ 边上的点
		for (auto fvit = (*p).fv_begin(p, *fit); fvit != (*p).fv_end(p, *fit); fvit++)
		{
			//如果无法触发断点请检查 C++>优化>的选项是否为【已禁用】，如果不是请改为【已禁用】。

			printf(" vertex id :%d", quote(fvit)->id);	//id是【顶点序号】，两个ID一组连成一条线
			//printf("fv point :%.9f %.9f %.9f \n", (*fvit).point[0], (*fvit).point[1], (*fvit).point[2]);
			int n(9);	// 点（结构体实例，对其修改不会影响真实的点）
		}

		std::cout << std::endl;
	}
	;
}

void print_cell(Mesh* p)
{
	printf("print cell vertex info ...\n");

	// cell - 多边形
	for (auto cit = p->c_begin(p); cit != p->c_end(p); cit++)
	{
		auto at = quote(cit);
		printf("cell id:%d", at->id);
		for (auto i = 0; i < quote(cit)->vertices_size; i++)
		{
			// 多边形的顶点坐标
			auto pvtx = at->vertices[i]->point;
			std::cout << " point:(" << pvtx[0] << "," << pvtx[1] << "," << pvtx[2] << ")";
		}

		std::cout << std::endl;
	}
}
